#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use log_case;
use XTM;
use LinuxPC;
my $p1m_list="p1m_list";
my $p2m_list="p2m_list";

#******** Variable for DUT1---XTM8
my $dut1_external_ip     = "10.0.120.1";
my $dut1_mgmt_ip         = "192.168.10.81";
my $dut1_trusted_subnet  = "192.168.20.0/24";
my $dut1_external_if     =  "External";

#******** Variable for DUT2---XTM5
#my $dut2_external_ip     =  "172.17.17.1";
#my $dut2_mgmt_ip         =  "192.168.10.51";
#my $dut2_trusted_subnet  =  "172.100.1.0/24";
#my $dut2_external_if     =  "Ex_LA-2";
#******** Variable for DUT2---XTM25-w
my $dut2_external_ip     =  "172.17.1.15";
my $dut2_mgmt_ip         =  "192.168.10.25";
my $dut2_trusted_subnet  =  "172.100.1.0/24";
my $dut2_external_if     =  "External";

#******** Variable for PC1---NET4PC1(linux pc)
my $pc1_eth0_ip             = $ARGV[10] ? $ARGV[10]: "10.138.103.22";
my $pc1_eth1_ip             = $ARGV[11] ? $ARGV[11]: "192.168.20.2";


#******** Variable for PC2---NET2PC1](linux pc)
my $pc2_eth0_ip             = $ARGV[12] ? $ARGV[12]: "10.138.103.21";
my $pc2_eth1_ip             = $ARGV[13] ? $ARGV[13]: "172.100.1.22";

#-------------
# init
#-------------
#***************** new DUTs used for setting up the  BOVPN tunnel
my $dut1 = new XTM(eth1=>$dut1_mgmt_ip);
my $dut2 = new XTM(eth1=>$dut2_mgmt_ip);

#***************** new PCs used for testing multicast
my $pc1 = new LinuxPC(HostIP=>$pc1_eth0_ip, UserName=>'automation', Password=>'password', RootPassword=>'password');
my $pc2 = new LinuxPC(HostIP=>$pc2_eth0_ip, UserName=>'automation', Password=>'password', RootPassword=>'password');


my @ret;
my $pre_shared = "11111111";
my $gateway_name = "gateway.100";
my $tunnel_name = "tunnel.100";


#goto NOCHECK;

loginfo("[CheckEnv] Make sure pc1 and pc2 cannot ping each other.");
my @PC1result = $pc1->ping($pc2_eth1_ip,Count=>'3');
my @PC2result = $pc2->ping($pc1_eth1_ip,Count=>'3');
if( ($PC1result[0] eq "ok") || ($PC2result[0] eq "ok") ){    
    logerr("two pcs can communicate with each other, environment error.\n");
    exit 99;  ## data tunnel failed.
}

my $mode = "Main";
my $p1_auth = "MD5";
my $p1_encrypt = "DES";
my $p1_dhg = "Diffie-Hellman-Group2";


loginfo("Configure BOVPN between XTM5 and XTM8.");
@ret = $dut1->cli->configBovpn(
    local_ID_ip=>$dut1_external_ip,
    remote_ip=>$dut2_external_ip, 
    local_subnet=>$dut1_trusted_subnet, 
    remote_subnet=>$dut2_trusted_subnet,
    mode=> $mode,
    local_if_alias => $dut1_external_if,
    gw_name=> $gateway_name,
    tunnel_name => $tunnel_name,
    pre_shared => $pre_shared,
    #method => $p1_auth,
    #encry => $p1_encrypt,
    #encry_length => '32',
    #key_group => $p1_dhg,
    nat_traversal => "disable",
    );
if($ret[0] eq 'nok'){
    logerr("Bovpn config DUT1 FAILED");
    exit 99; ## config failed
}
@ret = $dut2->cli->configBovpn(
    local_ID_ip=>$dut2_external_ip, 
    remote_ip=>$dut1_external_ip,
    local_subnet=>$dut2_trusted_subnet, 
    remote_subnet=>$dut1_trusted_subnet,
    mode=> $mode,
    local_if_alias => $dut2_external_if,
    gw_name=> $gateway_name,
    tunnel_name => $tunnel_name,
    pre_shared => $pre_shared,
    #method => $p1_auth,
    #encry => $p1_encrypt,
    #encry_length => '32',
    #key_group => $p1_dhg,
    nat_traversal => "disable",
    );
if($ret[0] eq 'nok'){
    logerr("Error: Bovpn config DUT2 FAILED\n");
    exit 99; ## config failed
}

loginfo("[CheckEnv] after bovpn configured, two PCs should be able to ping each other");
$pc1->ping($pc2_eth1_ip,Count=>'3');
$pc2->ping($pc1_eth1_ip,Count=>'3');
@PC1result = $pc1->ping($pc2_eth1_ip,Count=>'5');
@PC2result = $pc2->ping($pc1_eth1_ip,Count=>'5');

if( ($PC1result[0] eq "ok") && ($PC2result[0] eq "ok") ){
    loginfo("2-way Ping Success, CheckEnv Pass, Start test cases now\n");  
}else{
    logerr("2-way Ping Failed, CheckEnv Failed\n");
    exit 99;  ## data tunnel failed.
}

#NOCHECK:

my $test_cnt=0;
my $p1_fail_cnt=0;
my $p2_fail_cnt=0;

loginfo("This script will test all combinations of BOVPN encryption and HMAC algorithm in main mode\n");

loginfo("Part.1, test phase 1 transform combinations\n");
open(P1,"<$p1m_list") or die "Unable to open p1 combination list: $!";
my @fc=<P1>;
close(P1);


#goto PHASE2;

foreach my $each_line (@fc){
    my ($mode, $phase, $hmac, $encrypt, $dhg) = split(/ /, $each_line);
    $test_cnt++;
    chomp($dhg);
    loginfo("[$test_cnt] $hmac-$encrypt-$dhg:");
    config_p1("$hmac-$encrypt-$dhg", $dut1);
    if (ping_check("$hmac-$encrypt-$dhg") == 0){
        logerr("P1 $hmac-$encrypt-$dhg: both side different but ping success, environment error!!");
        continue;
    }
    config_p1("$hmac-$encrypt-$dhg", $dut2);
    $p1_fail_cnt += ping_check("$hmac-$encrypt-$dhg");
}

#PHASE2:

@fc=();

loginfo("Part.2, test phase 2 proposal combinations\n");
open(P1,"<$p2m_list") or die "Unable to open p1 combination list: $!";
@fc=<P1>;
close(P1);
foreach my $each_line (@fc){
    my ($mode, $phase, $proto, $hmac, $encrypt, $dhg) = split(/ /, $each_line);
    $test_cnt++;
    chomp($dhg);
    loginfo("[$test_cnt] $proto-$hmac-$encrypt-$dhg:");
    config_p2("$proto-$hmac-$encrypt-$dhg", $dut1);
    if (ping_check("$proto-$hmac-$encrypt-$dhgg") == 0){
        logerr("P2 $proto-$hmac-$encrypt-$dhgg: both side different but ping success, environment error!!");
        continue;
    }
    config_p2("$proto-$hmac-$encrypt-$dhg", $dut2);
    $p2_fail_cnt += ping_check("$proto-$hmac-$encrypt-$dhg");
    clear_p2proposal("$proto-$hmac-$encrypt-$dhg");
}

loginfo("Totally $test_cnt cases, Phase1 test failed $p1_fail_cnt, phase2 test failed $p2_fail_cnt.");

sub config_p1{
    my $transform=shift;
    
    my @dutlist=@_;
    
    my @cmd_list=("config","policy", "bovpn-gateway $gateway_name");
    
    my ($hmac, $encrypt, $dhg) = split(/\-/, $transform);
    $hmac    = uc($hmac);
    $hmac    =~ s/\_/\-/g;
    $encrypt =~ s/3des/des-3/g;
    $encrypt = uc($encrypt);
    $dhg     =~ s/dhg(\d)/Diffie-Hellman-Group$1/;
    
    if ($encrypt =~ /aes(\d{3})bit/i){
        my $keylen = $1;
        $keylen = $keylen/8;
        push(@cmd_list,"phase1 transform $hmac AES 0 encryp-key-length $keylen $dhg");
    }else{
        push(@cmd_list,"phase1 transform $hmac $encrypt 0 $dhg");
    }
    
    push(@cmd_list,"no phase1 transform 1","apply","exit","exit","exit");
    
    foreach my $dut (@dutlist){
        $dut->cli->connect_cli();
        $dut->cli->cmd(@cmd_list);
        #$dut->cli->disconnect();
        loginfo("$transform configuration complete on $dut");
    }
}

sub config_p2{
    my $transform = shift;
    my @dutlist = @_;

    my @cmd_list = ("config","policy");

    my ($proto, $hmac, $encrypt, $dhg) = split(/\-/, $transform);
    $hmac =~ s/\_/\-/g;
    $encrypt =~ s/bit//g;

    # Add corresponding phase 2 proposal
    if ($proto eq "esp"){
        loginfo("creating ESP proposal: ");
        push(@cmd_list, "proposal p2 $transform $proto transform 0 0 $encrypt $hmac","apply");
    }elsif($proto eq "ah"){
        loginfo("creating AH proposal: ");
        push(@cmd_list, "proposal p2 $transform $proto transform 0 0 $hmac","apply");
    }else{
        logerr("Unknown protocol, must be esp or ah.");
    }
    # Replace all proposals with current one
    push(@cmd_list, "bovpn-tunnel $tunnel_name", "phase2 proposals $transform replace yes");
    
    # if $dhg matched dhg\d, mean dhg will enabled,get the dhg number and form command
    if ($dhg =~ /dhg\d/){
        $dhg =~ s/dhg(\d)/dh-group$1/g;
        push(@cmd_list, "phase2 pfs enable $dhg");
    }else{
        # If $dhg did not match dhg, means $dhg=nodhg, disable pfs to make sure PFS is disabled
        push(@cmd_list, "no phase2 pfs enable");
    }
    push(@cmd_list, "apply", "exit", "exit", "exit");
    
    foreach my $dut (@dutlist){
        $dut->cli->connect_cli();
        $dut->cli->cmd(@cmd_list);
        #$dut->cli->disconnect();
    }
}

sub clear_p2proposal{
    my $p2name = shift;
    my @dutlist = @_;
    my @cmd_list = ("config","policy");
    push(@cmd_list, "no proposal p2 $p2name","apply","exit","exit");
    
    foreach my $dut (@dutlist){
        $dut->cli->connect_cli();
        $dut->cli->cmd(@cmd_list);
        #$dut->cli->disconnect();
    }
}

sub loginfo{
    my $str=shift;
    print "\nINFO::- $str\n";
}

sub logerr{
    my $str=shift;
    print "\nERR::- $str\n";
}

sub ping_check{
    my $title = shift;
    $pc1->ping($pc2_eth1_ip,Count=>'3');
    $pc2->ping($pc1_eth1_ip,Count=>'3');
    my @PC1result = $pc1->ping($pc2_eth1_ip,Count=>'5');
    my @PC2result = $pc2->ping($pc1_eth1_ip,Count=>'5');

    if( ($PC1result[0] eq "ok") && ($PC2result[0] eq "ok") ){
        loginfo("[$title] Traffic Check Passed.\n"); 
        return 0;
    }else{
        logerr("[$title] Traffic Check Failed.\n");
        return 1;
    }
}

exit 0;
